Page({
  data: {
    results: [], // {text, points: [{x,y}...]}[]
    overlayReady: false,
  },

  onLoad() {
    this.camera = wx.createCameraContext();
    // 尝试加载 jsQR（支持QR多次解码实现“多码”）
    try {
      // 需放置到 utils/jsqr.js（jsQR 单文件版本）
      this.jsQR = require('../../utils/jsqr.js');
    } catch (e) {
      this.jsQR = null;
      console.warn('[multiscan] jsQR not found, will fallback to demo boxes', e);
    }
    // 尝试加载 ZXing（支持一维条码/二维码）
    try {
      this.ZXing = require('../../utils/zxing.umd.min.js');
    } catch (e) {
      this.ZXing = null;
      console.warn('[multiscan] ZXing not found, barcode formats will be unavailable', e);
    }
    const query = wx.createSelectorQuery();
    query.select('#overlay').fields({ node: true, size: true }).exec(res => {
      const canvas = res && res[0] && res[0].node;
      if (!canvas) return;
      this.canvas = canvas;
      this.ctx = canvas.getContext('2d');
      this.canvas.width = res[0].width;
      this.canvas.height = res[0].height;
      this.setData({ overlayReady: true });
      this.clearOverlay();
    });
  },

  onUnload() {
    this.camera = null;
  },

  clearOverlay() {
    if (!this.ctx) return;
    const { width, height } = this.canvas;
    this.ctx.clearRect(0, 0, width, height);
  },

  drawBoxes(detections) {
    if (!this.ctx) return;
    const ctx = this.ctx;
    const { width, height } = this.canvas;
    ctx.clearRect(0, 0, width, height);
    detections.forEach(det => {
      const pts = det.points || [];
      if (pts.length >= 4) {
        ctx.strokeStyle = 'rgba(34,197,94,0.95)';
        ctx.lineWidth = 4;
        ctx.beginPath();
        ctx.moveTo(pts[0].x, pts[0].y);
        for (let i = 1; i < pts.length; i++) ctx.lineTo(pts[i].x, pts[i].y);
        ctx.closePath();
        ctx.stroke();
      }
    });
  },

  async onCaptureAndDetect() {
    try {
      wx.showLoading({ title: '识别中', mask: true });
      const photo = await this.camera.takePhoto({ quality: 'high' });
      const imgPath = photo.tempImagePath;
      const { detections, values } = await this.detectMultiFromImage(imgPath);
      this.setData({ results: detections });
      this.drawBoxes(detections);
      if (!values || values.length === 0) {
        wx.showToast({ title: '未检测到码', icon: 'none' });
      } else {
        wx.showToast({ title: `识别到${values.length}个`, icon: 'success' });
        // 自动回传，避免再次选择
        setTimeout(() => { this.onConfirm(); }, 700);
      }
    } catch (e) {
      wx.showToast({ title: '拍照失败', icon: 'none' });
      console.warn('[multiscan] capture/detect error', e);
    } finally {
      wx.hideLoading();
    }
  },

  async detectMultiFromImage(imgPath) {
    // 将图片绘制到 overlay canvas 上获取像素并用 jsQR 反复解码，逐个抹除已识别区域以实现“多码”
    const ctx = this.ctx;
    const canvas = this.canvas;
    if (!ctx || !canvas) return { detections: [], values: [] };

    // 加载图片
    const img = canvas.createImage();
    await new Promise((resolve, reject) => {
      img.onload = resolve;
      img.onerror = reject;
      img.src = imgPath;
    });

    // 将图片等比缩放绘制到画布（覆盖全画布短边适配）
    const cw = canvas.width;
    const ch = canvas.height;
    ctx.clearRect(0, 0, cw, ch);
    const scale = Math.min(cw / img.width, ch / img.height);
    const dw = Math.round(img.width * scale);
    const dh = Math.round(img.height * scale);
    const dx = Math.round((cw - dw) / 2);
    const dy = Math.round((ch - dh) / 2);
    ctx.drawImage(img, dx, dy, dw, dh);

    // 如果既没有 jsQR 也没有 ZXing，返回演示数据
    if (!this.jsQR && !this.ZXing) {
      const pad = Math.min(cw, ch) * 0.08;
      const boxSize = Math.min(cw, ch) * 0.36;
      const det = (x, y, text) => ({
        text,
        points: [
          { x, y },
          { x: x + boxSize, y },
          { x: x + boxSize, y: y + boxSize },
          { x, y: y + boxSize }
        ]
      });
      const detections = [
        det(pad, pad, 'DEMO-CODE-1'),
        det(cw - pad - boxSize, ch - pad - boxSize, 'DEMO-CODE-2')
      ];
      const values = detections.map(d => d.text);
      return { detections, values };
    }

    // 多次解码（先尝试 QR，再尝试一维码/QR 的 ZXing）
    const results = [];
    const maxRounds = 8; // 防护
    // 1) QR 多次解码（jsQR）
    if (this.jsQR) {
      for (let round = 0; round < maxRounds; round++) {
        const imgData = ctx.getImageData(dx, dy, dw, dh);
        const qr = this.jsQR(imgData.data, imgData.width, imgData.height, { inversionAttempts: 'attemptBoth' });
        if (!qr || !qr.data) break;
        const mapPoint = (p) => ({ x: dx + p.x, y: dy + p.y });
        const points = [qr.location.topLeftCorner, qr.location.topRightCorner, qr.location.bottomRightCorner, qr.location.bottomLeftCorner].map(mapPoint);
        results.push({ text: qr.data, points });
        const xs = points.map(p => p.x);
        const ys = points.map(p => p.y);
        const minX = Math.max(Math.min.apply(null, xs) - 8, 0);
        const minY = Math.max(Math.min.apply(null, ys) - 8, 0);
        const maxX = Math.min(Math.max.apply(null, xs) + 8, cw);
        const maxY = Math.min(Math.max.apply(null, ys) + 8, ch);
        ctx.save();
        ctx.fillStyle = '#ffffff';
        ctx.fillRect(minX, minY, Math.max(1, maxX - minX), Math.max(1, maxY - minY));
        ctx.restore();
      }
    }

    // 2) 条形码/二维码 多次解码（ZXing）
    if (this.ZXing) {
      const ZX = this.ZXing;
      const reader = new ZX.MultiFormatReader();
      try {
        const hints = new ZX.Map();
        hints.set(ZX.DecodeHintType.POSSIBLE_FORMATS, [
          ZX.BarcodeFormat.QR_CODE,
          ZX.BarcodeFormat.CODE_128,
          ZX.BarcodeFormat.CODE_39,
          ZX.BarcodeFormat.EAN_13,
          ZX.BarcodeFormat.EAN_8,
          ZX.BarcodeFormat.UPC_A,
          ZX.BarcodeFormat.UPC_E,
          ZX.BarcodeFormat.ITF,
          ZX.BarcodeFormat.CODABAR,
          ZX.BarcodeFormat.PDF_417
        ]);
        // 尝试更强容错
        hints.set(ZX.DecodeHintType.TRY_HARDER, true);
        reader.setHints(hints);
      } catch (e) {
        // 某些 UMD 版本没有 Map/Hint，忽略
      }

      for (let round = 0; round < maxRounds; round++) {
        let res = null;
        try {
          const imgData = ctx.getImageData(dx, dy, dw, dh);
          // 将 RGBA 转灰度
          const data = imgData.data;
          const luminances = new Uint8ClampedArray(imgData.width * imgData.height);
          for (let i = 0, j = 0; i < data.length; i += 4, j++) {
            // BT.601 加权
            luminances[j] = ((data[i] * 299 + data[i + 1] * 587 + data[i + 2] * 114 + 500) / 1000) | 0;
          }
          const source = new ZX.RGBLuminanceSource(luminances, imgData.width, imgData.height);
          const bitmap = new ZX.BinaryBitmap(new ZX.HybridBinarizer(source));
          try {
            res = reader.decodeWithState(bitmap);
          } catch (err1) {
            try { res = reader.decode(bitmap); } catch (err2) { res = null; }
          }
        } catch (e) {
          res = null;
        }

        if (!res) break;

        // 结果提取
        const text = (typeof res.getText === 'function') ? res.getText() : (res.text || '');
        let pts = [];
        try {
          const rps = (typeof res.getResultPoints === 'function') ? res.getResultPoints() : (res.resultPoints || []);
          pts = (rps || []).map(p => ({ x: (typeof p.getX === 'function') ? p.getX() : p.x, y: (typeof p.getY === 'function') ? p.getY() : p.y }))
            .map(p => ({ x: dx + p.x, y: dy + p.y }));
        } catch (_) { pts = []; }

        // 将 1D 的两点扩展为矩形，便于绘制与擦除
        let boxPoints = pts;
        if (!boxPoints || boxPoints.length < 4) {
          const xs = (pts && pts.length ? pts : [{ x: dx, y: dy }, { x: dx + dw, y: dy + dh }]).map(p => p.x);
          const ys = (pts && pts.length ? pts : [{ x: dx, y: dy }, { x: dx + dw, y: dy + dh }]).map(p => p.y);
          const minX = Math.max(Math.min.apply(null, xs) - 10, 0);
          const minY = Math.max(Math.min.apply(null, ys) - 10, 0);
          const maxX = Math.min(Math.max.apply(null, xs) + 10, cw);
          const maxY = Math.min(Math.max.apply(null, ys) + 10, ch);
          boxPoints = [
            { x: minX, y: minY },
            { x: maxX, y: minY },
            { x: maxX, y: maxY },
            { x: minX, y: maxY }
          ];
        }

        results.push({ text, points: boxPoints });

        // 擦除该区域，扩大一些边距
        const xs2 = boxPoints.map(p => p.x);
        const ys2 = boxPoints.map(p => p.y);
        const minX2 = Math.max(Math.min.apply(null, xs2) - 8, 0);
        const minY2 = Math.max(Math.min.apply(null, ys2) - 8, 0);
        const maxX2 = Math.min(Math.max.apply(null, xs2) + 8, cw);
        const maxY2 = Math.min(Math.max.apply(null, ys2) + 8, ch);
        ctx.save();
        ctx.fillStyle = '#ffffff';
        ctx.fillRect(minX2, minY2, Math.max(1, maxX2 - minX2), Math.max(1, maxY2 - minY2));
        ctx.restore();
      }
    }

    // 去重
    const uniq = [];
    const seen = new Set();
    results.forEach(r => {
      const k = String(r.text);
      if (seen.has(k)) return;
      seen.add(k);
      uniq.push(r);
    });
    return { detections: uniq, values: uniq.map(r => r.text) };
  },

  onConfirm() {
    const pages = getCurrentPages();
    const prev = pages[pages.length - 2];
    const channel = this.getOpenerEventChannel && this.getOpenerEventChannel();
    const values = (this.data.results || []).map(r => r.text);
    if (channel) channel.emit('multiScanResult', { values, detections: this.data.results });
    wx.navigateBack();
  },

  onCancel() {
    wx.navigateBack();
  }
});


